package monitor

import (
	"context"
	"encoding/json"
	"fmt"
	"gitee.com/aldrice/monitor/ent"
	"gitee.com/aldrice/monitor/ent/alarmlog"
	"gitee.com/aldrice/monitor/ent/metric"
	. "gitee.com/aldrice/monitor/internal/common"
	"gitee.com/aldrice/monitor/internal/mail"
	"gitee.com/aldrice/monitor/internal/registry"
	"gitee.com/aldrice/monitor/pkg/logging"
	"github.com/streadway/amqp"
	"go.uber.org/zap"
	"time"
)

// SendEmail 邮件发送模块
type SendEmail struct {
}

// Behavior 邮件发送模块处理方法
func (s *SendEmail) Behavior(msg amqp.Delivery) (string, error) {

	fmt.Println("进入邮件发送模块")

	ctx := context.Background()

	// 读取消息
	emailMsg := EmailMsg{}
	err := json.Unmarshal(msg.Body, &emailMsg)
	if err != nil {
		return "fail to Unmarshal message", err
	}

	// 获取object信息
	obj, err := registry.Ent().Object.Get(ctx, emailMsg.Id)
	if err != nil {
		return "fail to get object", err
	}

	// 告警邮件发送
	if err := sendNotify(obj, emailMsg.Details, emailMsg.MaxAlarm); err != nil {
		return "failed to send alarm notification", err
	}
	return "", nil

}

// sendNotify 发送邮件
// 发送频率为30min
func sendNotify(obj *ent.Object, items []AlarmItem, max int) error {
	ctx, cancel := context.WithTimeout(context.Background(), time.Second*10)
	defer cancel()
	owners, err := obj.QueryOwnedBy().All(ctx)
	if err != nil {
		return err
	}
	for _, item := range items {
		// 检查30分钟内, 该机器是否有同指标, 等于或更高告警等级的记录, 如果有则表明已经发送过邮件, 不再发送
		amount, err := obj.QueryHasLogs().Where(
			alarmlog.HasSentForMetricWith(metric.NameEqualFold(item.Metric)),
			alarmlog.RecordLevelGTE(max),
			alarmlog.AlarmAtGT(time.Now().Add(-time.Minute*30)),
		).Count(ctx)
		if err != nil {
			return err
		}
		if amount >= 2 {
			continue
		}

		// 发送邮件
		go sendNotifyEmails(owners, obj, item)
	}
	return nil
}

// sendNotifyEmails
func sendNotifyEmails(owners []*ent.User, object *ent.Object, item AlarmItem) {
	item.ObjectID = fmt.Sprintf("%d", object.ID)
	for _, o := range owners {
		err := mail.SendMessage(
			o.Username,
			fmt.Sprintf("%s (公网IP: %s)", object.Nickname, object.PublicAddress),
			o.Email,
			item,
			mail.EmailTypeNotify,
		)
		if err != nil {
			logging.Logger().Error(
				"failed to send email",
				zap.String("type", string(mail.EmailTypeNotify)),
				zap.Error(err),
			)
		}
	}
}
